<?php
/**
 * factoryメソッドのテスト
 * 
 * @since 2012/02/22
 */
class TestofYuToriFactory extends UnitTestCase {
	public function __construct () {
	}

	// 試験汎用
	// 第1引数のみ指定
	private function _CommonTest_01 ($value, $type) {
		$y = YuTori::factory($value);
		$this->assertIdentical($res = $y->getType() , $type, '型判定');
		$this->assertIdentical($res = $y->getName() , '', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , '', 'セレクタ判定');
		$this->assertIdentical($res = $y->get() , $value, 'get値判定');
		$this->assertIdentical($res = $y->call() , $value, 'call値判定');
	}
	private function _CommonTestY_01 ($value, $type, $instance) {
		$y = YuTori::factory($value);
		$this->assertIdentical($res = $y->getType() , $type, '型判定');
		$this->assertIdentical($res = $y->getName() , '', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , '', 'セレクタ判定 ');
		$this->assertIdentical($res = $y->get() , $instance, 'get値判定');
		$this->assertIdentical($res = $y->call() , $instance, 'call値判定');
	}

	// 第2引数まで指定
	private function _CommonTest_02 ($value, $type) {
		$y = YuTori::factory($value, 'testName');
		$this->assertIdentical($res = $y->getType() , $type, '型判定');
		$this->assertIdentical($res = $y->getName() , 'testName', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , 'testName', 'セレクタ判定');
		$this->assertIdentical($res = $y->get() , $value, 'get値判定');
		$this->assertIdentical($res = $y->call() , $value, 'call値判定');
	}
	private function _CommonTestY_02 ($value, $type, $instance) {
		$y = YuTori::factory($value);
		$this->assertIdentical($res = $y->getType() , $type, '型判定');
		$this->assertIdentical($res = $y->getName() , $value->getName(), '名称判定');
		$this->assertIdentical($res = $y->getSelector() , $value->getSelector(), 'セレクタ判定 ');
		$this->assertIdentical($res = $y->get() , $instance, 'get値判定');
		$this->assertIdentical($res = $y->call() , $instance, 'call値判定');
	}

	// 第3引数まで指定
	private function _CommonTest_03 ($value, $type) {
		$y = YuTori::factory($value, 'testName', array(0,1,2));
		$this->assertIdentical($res = $y->getType() , $type, '型判定');
		$this->assertIdentical($res = $y->getName() , 'testName', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , 'testName', 'セレクタ判定');
		$this->assertIdentical($res = $y->get() , $value, 'get値判定');
		$this->assertIdentical($res = $y->call() , $value, 'call値判定');
		$this->assertIdentical($res = $y->child()->get() , array(0,1,2), 'child判定');
	}
	private function _CommonTestY_03 ($value, $type, $instance) {
		$y = YuTori::factory($value, null, array(0,1,2));
		$this->assertIdentical($res = $y->getType() , $type, '型判定');
		$this->assertIdentical($res = $y->getName() , $value->getName(), '名称判定');
		$this->assertIdentical($res = $y->getSelector() , $value->getSelector(), 'セレクタ判定 ');
		$this->assertIdentical($res = $y->get() , $instance, 'get値判定');
		$this->assertIdentical($res = $y->call() , $instance, 'call値判定');
		$this->assertIdentical($res = $y->child()->get() , array(0,1,2), 'child判定');
	}

	// TYPE_SCALAR
	public function TestofScalar() {
		$this->_CommonTest_01 ('Test', YuTori::TYPE_SCALAR);
		$this->_CommonTest_02 ('Test', YuTori::TYPE_SCALAR);
		$this->_CommonTest_03 ('Test', YuTori::TYPE_SCALAR);
		$this->_CommonTest_01 (1, YuTori::TYPE_SCALAR);
		$this->_CommonTest_02 (1, YuTori::TYPE_SCALAR);
		$this->_CommonTest_03 (1, YuTori::TYPE_SCALAR);
	}

	// TYPE_BOOL
	// booleanは２つしかないのでどっちも試験する。
	public function TestofBool() {
		$this->_CommonTest_01 (true, YuTori::TYPE_BOOL);
		$this->_CommonTest_02 (true, YuTori::TYPE_BOOL);
		$this->_CommonTest_03 (true, YuTori::TYPE_BOOL);
		$this->_CommonTest_01 (false, YuTori::TYPE_BOOL);
		$this->_CommonTest_02 (false, YuTori::TYPE_BOOL);
		$this->_CommonTest_03 (false, YuTori::TYPE_BOOL);
	}

	// TYPE_NULL
	public function TestofNull() {
		$this->_CommonTest_01 (null, YuTori::TYPE_NULL);
		$this->_CommonTest_02 (null, YuTori::TYPE_NULL);
		$this->_CommonTest_03 (null, YuTori::TYPE_NULL);
	}

	// TYPE_ARRAY
	public function TestofArray() {
		$arr = array(0,1,2);
		$this->_CommonTest_01 ($arr, YuTori::TYPE_ARRAY);
		$this->_CommonTest_02 ($arr, YuTori::TYPE_ARRAY);

		// 連想配列の場合
		$arr = array('a'=>'apple', 'b'=>'orange', 'c'=>'sugar');
		$this->_CommonTest_01 ($arr, YuTori::TYPE_ARRAY);
		$this->_CommonTest_02 ($arr, YuTori::TYPE_ARRAY);


		// 二次元配列の場合
		$arr = array(array(0,1,2),array('a'=>'apple', 'b'=>'orage'),2);
		$this->_CommonTest_01 ($arr, YuTori::TYPE_ARRAY);
		$this->_CommonTest_02 ($arr, YuTori::TYPE_ARRAY);
		
		// 第三引数は共通化できないので個別で。
		$arr = array(0,1,2);
		$y = YuTori::factory($arr, 'testName', $arr);
		$this->assertIdentical($res = $y->getType() , YuTori::TYPE_ARRAY, '型判定');
		$this->assertIdentical($res = $y->getName() , 'testName', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , 'testName', 'セレクタ判定');
		$this->assertIdentical($res = $y->count() , 6, 'child数判定');
		$this->assertIdentical($res = $y->get() , array(0,1,2,0,1,2), 'get値判定');
		$this->assertIdentical($res = $y->call() , array(0,1,2,0,1,2), 'call値判定');
		$this->assertIdentical($res = $y->child()->get() , array(0,1,2,0,1,2), 'child判定');

		$arr1 = array(0,1,2, 'a'=>'apple');
		$arr2 = array(0,1,2, 'a'=>'orange', 'c'=>'apple');
		$y = YuTori::factory($arr1, 'testName', $arr2);
		$this->assertIdentical($res = $y->getType() , YuTori::TYPE_ARRAY, '型判定');
		$this->assertIdentical($res = $y->getName() , 'testName', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , 'testName', 'セレクタ判定');
		$this->assertIdentical($res = $y->count() , 9, 'child数判定');
		$this->assertIdentical($res = $y->get() , array(0,1,2,'a'=>'orange', 0,1,2, 'c'=>'apple'), 'get値判定');
		$this->assertIdentical($res = $y->call() , array(0,1,2,'a'=>'orange', 0,1,2,'c'=>'apple'), 'call値判定');
		$this->assertIdentical($res = $y->child()->get() , array(0,1,2,'a'=>'orange',0,1,2,'c'=>'apple'), 'child判定'.print_r($res, 1));
	}
	// TYPE_OBJECT
	public function TestofObject() {
		$obj = new stdClass();
		$this->_CommonTest_01 ($obj, YuTori::TYPE_OBJECT);
		$this->_CommonTest_02 ($obj, YuTori::TYPE_OBJECT);
		$this->_CommonTest_03 ($obj, YuTori::TYPE_OBJECT);
	}

	// TYPE_CALLABLE
	public function TestofCallable() {
		// 第四引数指定から開始
		$y = YuTori::factory('myFunc', 'myFuncName', array(), YuTori::TYPE_CALLABLE);
		$this->assertIdentical($y->getType() , YuTori::TYPE_CALLABLE, '型判定');
		$this->assertIdentical($y->getName() , 'myFuncName', '名称判定');
		$this->assertIdentical($y->getSelector() , 'myFuncName', 'セレクタ判定');
		$this->assertIdentical($y->get() , 'myFunc', 'get値判定');
		$this->assertIdentical($y->call() , 'Func!', 'call値判定');

		// メソッドの時
		$func = array(new myClass(), 'func');
		$y = YuTori::factory($func, 'myFuncName', array(), YuTori::TYPE_CALLABLE);
		$this->assertIdentical($y->getType() , YuTori::TYPE_CALLABLE, '型判定');
		$this->assertIdentical($y->getName() , 'myFuncName', '名称判定');
		$this->assertIdentical($y->getSelector() , 'myFuncName', 'セレクタ判定');
		$this->assertTrue($y->get() == $func , 'get値判定');
		$this->assertIdentical($y->call() , 'Method!', 'call値判定');

		// 存在しない関数
		$y = YuTori::factory('myFunc2', 'myFuncName2', array(), YuTori::TYPE_CALLABLE);
		$this->assertIdentical($y->getType() , YuTori::TYPE_EMPTY, '型判定');
		$this->assertIdentical($y->getName() , null, '名称判定');
		$this->assertIdentical($y->getSelector() , null, 'セレクタ判定');
		$this->assertIdentical($y->get() , null, 'get値判定');
		$this->assertIdentical($y->call() , null, 'call値判定');
		$this->assertTrue($y->isEmpty(), 'isEmpty値判定');

		// 存在しないメソッド
		$func = array(new myClass(), 'func2');
		$y = YuTori::factory($func, 'myFuncName', array(), YuTori::TYPE_CALLABLE);
		$this->assertIdentical($y->getType() , YuTori::TYPE_EMPTY, '型判定');
		$this->assertIdentical($y->getName() , null, '名称判定');
		$this->assertIdentical($y->getSelector() , null, 'セレクタ判定');
		$this->assertIdentical($y->get() , null, 'get値判定');
		$this->assertIdentical($y->call() , null, 'call値判定');
		$this->assertTrue($y->isEmpty(), 'isEmpty値判定');
	}

	// TYPE_FILE 

	// TYPE_YuToriObject
	public function TestofY_Scalar() {
		$y = YuTori::factory('test');
		$this->_CommonTestY_01 ($y, YuTori::TYPE_SCALAR, 'test');

		$y = YuTori::factory('test', 'testName');
		$this->_CommonTestY_02 ($y, YuTori::TYPE_SCALAR, 'test');

		$y = YuTori::factory('test', 'testName');
		$this->_CommonTestY_03 ($y, YuTori::TYPE_SCALAR, 'test');
	}
	public function TestofY_Bool() {
		$y = YuTori::factory(true);
		$this->_CommonTestY_01 ($y, YuTori::TYPE_BOOL, true);

		$y = YuTori::factory(true, 'testName');
		$this->_CommonTestY_02 ($y, YuTori::TYPE_BOOL, true);

		$y = YuTori::factory(true, 'testName');
		$this->_CommonTestY_03 ($y, YuTori::TYPE_BOOL, true);
	}
	public function TestofY_Null() {
		$y = YuTori::factory(null);
		$this->_CommonTestY_01 ($y, YuTori::TYPE_NULL, null);

		$y = YuTori::factory(null, 'testName');
		$this->_CommonTestY_02 ($y, YuTori::TYPE_NULL, null);

		$y = YuTori::factory(null, 'testName');
		$this->_CommonTestY_03 ($y, YuTori::TYPE_NULL, null);
	}
	public function TestofY_Array() {
		$y = YuTori::factory(array(0,1,2));
		$this->_CommonTestY_01 ($y, YuTori::TYPE_ARRAY, array(0,1,2));

		$y = YuTori::factory(array(0,1,2), 'testName');
		$this->_CommonTestY_02 ($y, YuTori::TYPE_ARRAY, array(0,1,2));

		// 第三引数は共通化できないので個別で。
		$obj = YuTori::factory(array(0,1,2),('testName'));
		$arr = array(0,1,2);
		$y = YuTori::factory($obj, null, $arr);
		$this->assertIdentical($res = $y->getType() , YuTori::TYPE_ARRAY, '型判定');
		$this->assertIdentical($res = $y->getName() , 'testName', '名称判定');
		$this->assertIdentical($res = $y->getSelector() , 'testName', 'セレクタ判定');
		$this->assertIdentical($res = $y->count() , 6, 'child数判定');
		$this->assertIdentical($res = $y->get() , array(0,1,2,0,1,2), 'get値判定');
		$this->assertIdentical($res = $y->call() , array(0,1,2,0,1,2), 'call値判定');
		$this->assertIdentical($res = $y->child()->get() , array(0,1,2,0,1,2), 'child判定');
	}
	public function TestofY_Object() {
		$y = YuTori::factory(new stdClass());
		$this->_CommonTestY_01 ($y, YuTori::TYPE_OBJECT, new stdClass());

		$y = YuTori::factory(new stdClass(), 'testName');
		$this->_CommonTestY_02 ($y, YuTori::TYPE_OBJECT, new stdClass());

		$y = YuTori::factory(new stdClass(), 'testName');
		$this->_CommonTestY_03 ($y, YuTori::TYPE_OBJECT, new stdClass());
	}
	
	// その他の試験
	// 使用できない名称:this
	public function TestofNoUseName () {
		$this->assertTrue(is_object(YuTori::factory ('this', 'thisSelector')), 'this前後に文字がある場合は例外は発生しない');

		try {
			YuTori::factory ('this', 'this');
		} catch (Exception $e) {
			var_dump ($e->getTrace());
		}
		$this->expectException(new Exception ('YuToriObject cannot be named "this"'), '名称にthisを指定した時の例外');
	}
}

function myFunc () {
	return 'Func!';
}

class myClass {
	function func () {
		return 'Method!';
	}
}